package org.eva.sagittarius.token.service.impl;

import java.util.Date;

import org.eva.sagittarius.token.constant.TokenType;
import org.eva.sagittarius.token.domain.Token;
import org.eva.sagittarius.token.domain.User;
import org.eva.sagittarius.token.exception.TokenException;
import org.eva.sagittarius.token.service.TokenService;
import org.eva.sagittarius.token.util.SHA1Util;
import org.eva.sagittarius.token.util.AESUtil;
import org.eva.sagittarius.token.util.Base64Util;
import org.eva.sagittarius.token.util.HexUtil;
import org.eva.sagittarius.token.util.PropertiesUtil;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;

import org.slf4j.Logger;

/**
 * 令牌服务接口的实现类
 * @author lishen
 *
 */
public class TokenServiceImpl implements TokenService {

	/**
	 * 日志记录器
	 */
	private static Logger logger = LoggerFactory.getLogger(TokenServiceImpl.class);

	/**
	 * AES加密算法的秘钥
	 */
	private static final String aesPassword = PropertiesUtil.getValue("config.properties", "aes.password");

	/**
	 * 将token对象转换为令牌（String格式）
	 * @param token
	 * @return
	 * @throws TokenException
	 */
	public String createTokenString(Token token) throws TokenException {
		if(null==token){
			logger.debug("方法toTokenString的参数为null");
			return null;
		}

		if(null==token.getVersion() || token.getVersion().equals("")){
			logger.error("token对象的version属性不能为null，也不能是空字符串");
			throw new TokenException("令牌的version属性不能为null,也不能为空字符串");
		}

		StringBuffer result=new StringBuffer();

		// 判断，填充version
		if(token.getVersion().equals(TokenType.CODE)){
			result.append(TokenType.CODE);
		}else if(token.getVersion().equals(TokenType.ACCESS_TOKEN)){
			result.append(TokenType.ACCESS_TOKEN);
		}else{
			logger.error("token对象的version属性只能是0x01,或者0x02");
			throw new TokenException("令牌的version属性只能是0x01,或者0x02");
		}

		// 判断，填充loginTime
		if(null==token.getLoginTime() || token.getLoginTime().after(new Date())){
			logger.error("token对象的loginTime属性不能为null，并且必须比现在的时间要早");
			throw new TokenException("令牌的loginTime属性不能为null，并且必须比现在的时间要早");
		}else{
			result.append(HexUtil.dateToHex(token.getLoginTime()));
		}

		// 判断，填充expirationTime
		if(null==token.getExpirationTime() || token.getExpirationTime().before(new Date())){
			logger.error("token对象的expirationTime属性不能为null，并且必须比现在的时间要晚");
			throw new TokenException("令牌的expirationTime属性不能为null，并且必须比现在的时间要晚");
		}else{
			result.append(HexUtil.dateToHex(token.getExpirationTime()));
		}

		// 判断，填充user
		String userString=JSON.toJSONString(token.getUser());
		result.append(userString);
//		if(null!=token.getUser()){
//			String userString=JSON.toJSONString(token.getUser());
//			result.append(AESUtil.aesEncrypt(userString, aesPassword));
//		}else{
//			result.append(AESUtil.aesEncrypt("", aesPassword));
//		}

		return result.toString();
	}

	/**
	 * 对令牌进行加密
	 * @param tokenString
	 * @return
	 */
	public String encrypt(String tokenString){
		// 使用SHA1计算校验和，并将其放在令牌的最后
		String userInfo=tokenString.substring(20, tokenString.length());
		System.out.println("sha1Encrypt之前的userInfo："+userInfo);
		String d1=SHA1Util.sha1Encrypt(userInfo);
		tokenString+=d1;

		// 使用SHA1算法，对整个令牌再计算一次校验和,并填充到原令牌数组里的最后40位里
		String d2=SHA1Util.sha1Encrypt(tokenString);
		tokenString=tokenString.substring(0, tokenString.length()-40)+d2;

		// 使用AES算法，对整个令牌进行加密
//		System.out.println("aes加密前，base64加密前："+tokenString);
		byte[] temp=AESUtil.aesEncrypt(tokenString, aesPassword);

		// 使用Base64算法，对整个令牌进行编码
		String result=null;
		try {
//			System.out.println("base64之前："+temp);
			result=Base64Util.encode(temp);
		} catch (Exception e) {
			e.printStackTrace();
		}

		return result;
	}

	/**
	 * 对令牌进行解密，并判断令牌是否被篡改。true：表示解密成功，令牌没有被篡改；false：表示解密失败，令牌被篡改了。
	 * @param tokenString
	 * @return
	 */
	public boolean decrypt(String tokenString){
		try {
			// 使用Base64对令牌进行解码
			byte[] b=Base64Util.decode(tokenString.toCharArray());

			// 使用AES算法对令牌进行解密
			tokenString=AESUtil.aesDecrypt(b, aesPassword);
//			System.out.println("base64解密后，aes解密后："+tokenString);

			// 去除令牌的最后40位，即校验字段
			String d1=tokenString.substring(tokenString.length()-40, tokenString.length());
			System.out.println("d1:");
			System.out.println(d1);

			// 从数据库中去除用户信息
			// 此处暂时采用硬编码
			User user=new User();
			user.setUsername("lisi");
			user.setPassword("abc");

			// 使用SHA1算法，针对对用户信息计算校验和
			String userString=JSON.toJSONString(user);
//			StringBuffer sb=new StringBuffer();
//			userString=sb.append(AESUtil.aesEncrypt(userString, aesPassword)).toString();
			System.out.println("sha1Encrypt之前的userString："+userString);
			userString=SHA1Util.sha1Encrypt(userString);

			// 将上一步计算出来的校验和填充到令牌的后40位中，再使用SHA1算法对整个数组计算校验和
			String temp=tokenString.substring(0, tokenString.length()-40)+userString;
			String d2=SHA1Util.sha1Encrypt(temp);

//			System.out.println(temp);
			System.out.println("d2:");
			System.out.println(d2);

			// 判断d1和d2是否相等，如果相等，则说明令牌没有被篡改。
			if(d1.equals(d2)){
				return true;
			}else{
				return false;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}

	/**
	 * 判断令牌是否过期。true：过期；false：没过期
	 * @param tokenString
	 * @return
	 */
	public boolean isExpiration(String tokenString){
		// 使用Base64对令牌进行解码
		byte[] b=Base64Util.decode(tokenString.toCharArray());

		// 使用AES算法对令牌进行解密
		tokenString=AESUtil.aesDecrypt(b, aesPassword);

		// 获取会话失效时间
		String expirationString=tokenString.substring(12, 20);
		Date expirationTime=HexUtil.hexToDate(expirationString);
		if(new Date().after(expirationTime)){
			return true;
		}else{
			return false;
		}
	}
}